package com.koushikdutta.ion.gson;

import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.TransformFuture;
import com.koushikdutta.async.parser.AsyncParser;
import com.koushikdutta.async.parser.ByteBufferListParser;
import com.koushikdutta.async.stream.ByteBufferListInputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public abstract class GsonParser<T extends JsonElement> implements AsyncParser<T> {
    Class<? extends JsonElement> clazz;

    public GsonParser(Class<? extends T> clazz) {
        this.clazz = clazz;
    }

    public Future<T> parse(DataEmitter emitter) {
        final String charset = emitter.charset() == null ? Charset.defaultCharset().name() : emitter.charset();
        return (Future) new ByteBufferListParser().parse(emitter).then(new TransformFuture<T, ByteBufferList>() {
            protected void transform(ByteBufferList result) throws Exception {
                JsonElement parsed = new JsonParser().parse(new JsonReader(new InputStreamReader(new ByteBufferListInputStream(result), charset)));
                if (parsed.isJsonNull() || parsed.isJsonPrimitive()) {
                    throw new JsonParseException("unable to parse json");
                } else if (GsonParser.this.clazz.isInstance(parsed)) {
                    setComplete(null, parsed);
                } else {
                    throw new ClassCastException(parsed.getClass().getCanonicalName() + " can not be casted to " + GsonParser.this.clazz.getCanonicalName());
                }
            }
        });
    }
}
